package ru.usu.gv.gui.dynamic;

import ru.usu.gv.core.GraphCanvas;
import ru.usu.gv.core.GraphEngine;
import ru.usu.gv.core.I18nService;
import ru.usu.gv.gui.GUIUtilities;
import ru.usu.gv.gui.actions.AddGraphAction;
import ru.usu.gv.gui.component.GVDoubleSlider;
import ru.usu.gv.gui.frames.HighlightDynamicEdgeFrame;
import ru.usu.gv.gui.layout.dynamic.DynamicLayoutUtilities;
import ru.usu.gv.styles.Style;
import ru.usu.gv.styles.StyleFacade;
import ru.usu.gv.utils.imports.DynamicGraphImporter;

import javax.media.j3d.BranchGroup;
import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.List;

/**
 * @author spupyrev
 * 06.11.2009
 */
public class DynamicVisPanel extends JPanel
{
	private static final DynamicVisPanel INSTANCE = new DynamicVisPanel();

	public static DynamicVisPanel getInstance()
	{
		return INSTANCE;
	}

	private GVDoubleSlider attractionExponentSlider;
	private GVDoubleSlider attractionFactorSlider;
	private GVDoubleSlider repulsionExponentSlider;
	private GVDoubleSlider repulsionFactorSlider;
	private GVDoubleSlider gravitationExponentSlider;
	private GVDoubleSlider gravitationFactorSlider;
	private GVDoubleSlider mentalExponentSlider;
	private GVDoubleSlider mentalFactorSlider;

	private DynamicVisPanel()
	{
		setVisible(false);
		setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));

		TitledBorder border = new TitledBorder(I18nService.get("layout.dynamic"));
		border.setTitlePosition(TitledBorder.TOP);
		border.setTitleJustification(TitledBorder.CENTER);
		border.setTitleColor(Color.BLUE);
		setBorder(border);

		JPanel chp = new JPanel();
		chp.setLayout(new GridLayout(2, 2, 3, 3));

		chp.add(createStartAutoLayoutPanel());
		chp.add(createShowSlicesCheckBox());

		add(chp);
		chp.add(GUIUtilities.prepareComponent(createLoadGraphButton(), 120, 20));
		chp.add(GUIUtilities.prepareComponent(createHighlightEdgesButton(), 120, 20));

		attractionExponentSlider = createSlider("Attraction exponent", 0, 5, "dynamiclayout.attractionExponent");
		add(attractionExponentSlider);

		attractionFactorSlider = createSlider("Attraction factor", 0, 100, "dynamiclayout.attractionFactor");
		add(attractionFactorSlider);

		repulsionExponentSlider = createSlider("Repulsion exponent", -5, 0, "dynamiclayout.repulsionExponent");
		add(repulsionExponentSlider);

		repulsionFactorSlider = createSlider("Repulsion factor", 0, 100, "dynamiclayout.repulsionFactor");
		add(repulsionFactorSlider);

		gravitationExponentSlider = createSlider("Gravitation exponent", 0, 5, "dynamiclayout.gravitationExponent");
		add(gravitationExponentSlider);

		gravitationFactorSlider = createSlider("Gravitation factor", 0, 100, "dynamiclayout.gravitationFactor");
		add(gravitationFactorSlider);

		mentalExponentSlider = createSlider("Mental exponent", 0, 5, "dynamiclayout.mentalExponent");
		add(mentalExponentSlider);

		mentalFactorSlider = createSlider("Mental factor", 0, 100, "dynamiclayout.mentalFactor");
		add(mentalFactorSlider);
	}

	private JButton createHighlightEdgesButton()
	{
		JButton button = new JButton(new AbstractAction(I18nService.get("layout.dynamic.select_edges"))
		{
			public void actionPerformed(ActionEvent e)
			{
				new HighlightDynamicEdgeFrame().setVisible(true);
			}
		});

		return button;
	}

	private GVDoubleSlider createSlider(String title, double min, double max, String stylePath)
	{
		Style style = StyleFacade.getCurrentStyle();

		GVDoubleSlider slider = new GVDoubleSlider(title, min, max, style.getDoubleAttribute(stylePath), true);
		slider.addChangeListener(new ChangeListener()
		{
			public void stateChanged(ChangeEvent e)
			{
				if (offlineFDCheckBox.isSelected())
					GraphEngine.getInstance().getOfflineDynamicVisBehavior().start();
				else if (onlineFDCheckBox.isSelected())
					GraphEngine.getInstance().getOnlineDynamicVisBehavior().start();
			}
		});
		return slider;
	}

	private JCheckBox createShowSlicesCheckBox()
	{
		JCheckBox showSlicesCheckBox = new JCheckBox(new AbstractAction(I18nService.get("layout.dynamic.show_slices"))
		{
			public void actionPerformed(ActionEvent e)
			{
				showSlices();
			}
		});
		return showSlicesCheckBox;
	}

	private JCheckBox onlineFDCheckBox;
	private JCheckBox offlineFDCheckBox;

	private JPanel createStartAutoLayoutPanel()
	{
		JPanel panel = new JPanel(new GridLayout(1, 2));
		panel.add(onlineFDCheckBox = createStartOnlineFDLayoutCheckBox());
		panel.add(offlineFDCheckBox = createStartOfflineFDLayoutCheckBox());
		return panel;
	}

	private JCheckBox createStartOnlineFDLayoutCheckBox()
	{
		JCheckBox showSlicesCheckBox = new JCheckBox(new AbstractAction("Online fd")
		{
			public void actionPerformed(ActionEvent e)
			{
				if (onlineFDCheckBox.isSelected())
					offlineFDCheckBox.setEnabled(false);
				else
					offlineFDCheckBox.setEnabled(true);

				GraphEngine.getInstance().getOnlineDynamicVisBehavior().setAutorun(onlineFDCheckBox.isSelected());
			}
		});
		showSlicesCheckBox.setFont(new Font(Font.DIALOG, Font.BOLD, 11));
		return showSlicesCheckBox;
	}

	private JCheckBox createStartOfflineFDLayoutCheckBox()
	{
		JCheckBox showSlicesCheckBox = new JCheckBox(new AbstractAction("Offline fd")
		{
			public void actionPerformed(ActionEvent e)
			{
				if (offlineFDCheckBox.isSelected())
					onlineFDCheckBox.setEnabled(false);
				else
					onlineFDCheckBox.setEnabled(true);

				GraphEngine.getInstance().getOfflineDynamicVisBehavior().setAutorun(offlineFDCheckBox.isSelected());
			}
		});
		showSlicesCheckBox.setFont(new Font(Font.DIALOG, Font.BOLD, 11));
		return showSlicesCheckBox;
	}

	private JButton createLoadGraphButton()
	{
		JButton loadGraphButton = new JButton();
		loadGraphButton.setAction(new AbstractAction(I18nService.get("layout.dynamic.load"))
		{
			public void actionPerformed(ActionEvent e)
			{
				String selectedFile = GUIUtilities.chooseOpenSaveFile(DynamicVisPanel.this, true);
				if (selectedFile != null)
				{
					try
					{
						AddGraphAction action = new AddGraphAction(DynamicGraphImporter.loadGraph(selectedFile));
						action.execute();
						GraphEngine.getInstance().getOfflineDynamicVisBehavior().start();
					}
					catch (Exception exc)
					{
						throw new RuntimeException(exc);
					}
				}
			}
		});
		return loadGraphButton;
	}

	private List<BranchGroup> slicesBranchGroup = null;

	protected void showSlices()
	{
		if (slicesBranchGroup == null)
		{
			slicesBranchGroup = DynamicLayoutUtilities.createSlicesBranchGroups(GraphCanvas.getInstance().getCurrentGraph());
			for (BranchGroup bg : slicesBranchGroup)
			{
				GraphCanvas.getInstance().addChild(bg);
			}
		}
		else
		{
			for (BranchGroup bg : slicesBranchGroup)
			{
				bg.detach();
			}
			slicesBranchGroup = null;
		}
	}

	public void changeVisibleState()
	{
		if (isVisible())
		{
			setVisible(false);
			GraphEngine.getInstance().getOfflineDynamicVisBehavior().stop();
		}
		else
		{
			setVisible(true);
			GraphEngine.getInstance().getOfflineDynamicVisBehavior().start();
		}
	}

	public double getAttractionExponent()
	{
		return attractionExponentSlider.getValue();
	}

	public double getAttractionFactor()
	{
		return attractionFactorSlider.getValue();
	}

	public double getRepulsionExponent()
	{
		return repulsionExponentSlider.getValue();
	}

	public double getRepulsionFactor()
	{
		return repulsionFactorSlider.getValue();
	}

	public double getGravitationExponent()
	{
		return gravitationExponentSlider.getValue();
	}

	public double getGravitationFactor()
	{
		return gravitationFactorSlider.getValue();
	}

	public double getMentalExponent()
	{
		return mentalExponentSlider.getValue();
	}

	public double getMentalFactor()
	{
		return mentalFactorSlider.getValue();
	}

}
